package homelesspartners.server;

import homelesspartners.client.ServerException;
import homelesspartners.client.Service;
import homelesspartners.client.model.Shelter;
import homelesspartners.client.model.Story;
import homelesspartners.client.model.ThankYou;
import homelesspartners.client.model.User;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.servlet.http.HttpSession;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ServiceImpl extends RemoteServiceServlet implements Service {

	private static final String DONE = "DONE";
	private static final String ERROR = " ERROR ";
	private static final String SPACE = " ";
	private static final String SESSION_KEY_USER = "HP.USER";
	private static final String SESSION_KEY_UNAUTHENTICATED_ID = "HP.ID";
	private static final long serialVersionUID = 1L;
	private static final String UID = "UID=";
	private static Object unauthenticatedIdLock = new Object();
	private static int unauthenticatedIdCount = 0;
	
	public ArrayList getCities() {
		final String method = "getCities()";
		logStart(method, new String[0]);
		Data data = new Data();
		ArrayList cityList = null;
		try {
			cityList = data.getCities();
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method);
		return cityList;
	}

	private void logStop(String method) {
		logStop(method, null);
	}

	private void logStop(String method, String error) {
		if (error != null) {
			System.out.println(ERROR + error);
		}
		long threadId = Thread.currentThread().getId();
		User user = getUser();
		int userId = getUnauthenticatedId();
		if (user != null) {
			userId = user.getUserId();
		}
		StringBuffer buffer = new StringBuffer();
		buffer.append(getTimestamp());
		buffer.append(SPACE);
		buffer.append(threadId);
		buffer.append(SPACE);
		buffer.append(UID);
		buffer.append(userId);
		buffer.append(SPACE);
		buffer.append(method);
		buffer.append(SPACE);
		buffer.append(DONE);

		System.out.println(buffer.toString());
	}

	private int getUnauthenticatedId() {
		HttpSession session = getThreadLocalRequest().getSession();
		Integer unauthenticatedId = (Integer) session.getAttribute(SESSION_KEY_UNAUTHENTICATED_ID);
		if (unauthenticatedId == null) {
			synchronized (unauthenticatedIdLock) {
				unauthenticatedIdCount--;
				unauthenticatedId = new Integer(unauthenticatedIdCount);
			}
			session.setAttribute(SESSION_KEY_UNAUTHENTICATED_ID, unauthenticatedId);
		}
		return unauthenticatedId.intValue();
	}

	private void logStart(String method, String[] args) {
		long threadId = Thread.currentThread().getId();
		User user = getUser();
		int userId = getUnauthenticatedId();
		if (user != null) {
			userId = user.getUserId();
		}
		StringBuffer buffer = new StringBuffer();
		buffer.append(getTimestamp());
		buffer.append(SPACE);
		buffer.append(threadId);
		buffer.append(SPACE);
		buffer.append(UID);
		buffer.append(userId);
		buffer.append(SPACE);
		buffer.append(method);
		for (int x = 0; x < args.length; x++) {
			buffer.append(SPACE);
			buffer.append(args[x]);
		}
		System.out.println(buffer.toString());

	}

	private String getTimestamp() {
		return DateFormat.getInstance().format(new Date());
	}

	public ArrayList getShelters(int cityId) {
		final String method = "getShelters()";
		logStart(method, new String[] { "" + cityId });
		Data data = new Data();
		ArrayList shelterList = null;
		try {
			shelterList = data.getShelters(cityId);
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method);
		return shelterList;
	}

	public ArrayList getStories(int shelterId, String idQuery, String nameQuery) {
		final String method = "getStories()";
		logStart(method, new String[] { "" + shelterId, idQuery, nameQuery });
		Data data = new Data();
		ArrayList storyList = null;
		try {
			storyList = data.getStories(shelterId, idQuery, nameQuery);
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method);
		return storyList;
	}

	public boolean pledgeGift(int giftId) throws ServerException {
		final String method = "pledgeGift()";
		logStart(method, new String[] { "" + giftId });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		try {
			boolean result = data.recordPledge(giftId, user.getUserId());
			if (result) {
				logStop(method);
			} else {
				logStop(method, "pledge gift result was false");
			}
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not pledge gift");
		return false;
	}

	private User getUser() {
		HttpSession session = getThreadLocalRequest().getSession();
		User user = (User) session.getAttribute(SESSION_KEY_USER);
		return user;
	}

	public User login(String userId, String password) {
		final String method = "login()";
		logStart(method, new String[] { userId, password });
		User userCheck = getUser();
		if (userCheck != null) {
			System.out.println(ERROR + "user was already logged in");
		}
		Data data = new Data();
		try {
			User user = data.login(userId, password);
			if (user == null) {
				logStop(method, "login failed");
				return user;
			}
			HttpSession session = getThreadLocalRequest().getSession();
			session.setAttribute(SESSION_KEY_USER, user);
			logStop(method);
			return user;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "did not login");
		return null;
	}

	public User createNewUser(String userId, String password) {
		final String method = "createNewUser()";
		logStart(method, new String[] { userId, password });
		Data data = new Data();
		try {
			User user = data.createNewUser(userId, password);
			HttpSession session = getThreadLocalRequest().getSession();
			session.setAttribute(SESSION_KEY_USER, user);
			logStop(method);
			return user;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not create user");
		return null;
	}

	public ArrayList getShoppingList() {
		final String method = "getShoppingList()";
		logStart(method, new String[0]);
		Data data = new Data();
		User user = getUser();
		try {
			ArrayList gifts = data.getShoppingList(user.getUserId());
			logStop(method);
			return gifts;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not get the shopping list");
		return null;
	}

	public Story addInterview(Story story) throws ServerException {
		final String method = "addInterview()";
		logStart(method, new String[] { story.toString() });
		if (story.validate() != null) {
			logStop(method, "story was invalid");
			return null;
		}
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		Data data = new Data();

		try {
			Story returnedStory = data.addInterview(story);
			logStop(method);
			return returnedStory;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not add the interview");
		return null;
	}

	public ArrayList addInterviewCheckFirst(Story story) throws ServerException {
		final String method = "addInterviewCheckFirst()";
		logStart(method, new String[] { story.toString() });
		if (story.validate() != null) {
			logStop(method, "story was invalid");
			return null;
		}
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		Data data = new Data();

		try {
			ArrayList returnedStories = data.addInterviewCheckFirst(story);
			logStop(method);
			return returnedStories;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not add the interview");
		return null;
	}

	private void checkTimeout(final String method, User user) throws ServerException {
		if (user == null) {
			ServerException exception = new ServerException();
			exception
					.setMessage("Your session has expired due to inactivity.  Please refresh the page to login again.");
			logStop(method, "session expired");
			throw exception;
		}
	}

	public Boolean unpledgeGift(int giftId) throws ServerException {
		final String method = "unpledgeGift()";
		logStart(method, new String[] { "" + giftId });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		try {
			Boolean result = data.removePledge(giftId, user.getUserId());
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not unpledge the gift");
		return false;
	}

	public Boolean deleteStory(int storyId) throws ServerException {
		final String method = "deleteStory()";
		logStart(method, new String[] { "" + storyId });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return false;
		}
		try {
			Boolean result = data.deleteStory(storyId);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not delete the story");
		return false;
	}

	public Story updateStory(Story updatedStory) throws ServerException {
		final String method = "updateStory()";
		logStart(method, new String[] { updatedStory.toString() });
		if (updatedStory.validate() != null) {
			logStop(method, "story was invalid");
			return null;
		}
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return null;
		}
		try {
			Story result = data.updateStory(updatedStory);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not update the story");
		return null;
	}

	public Boolean updateVolunteer(User volunteer) throws ServerException {
		final String method = "updateVolunteer()";
		logStart(method, new String[] { volunteer.toString() });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() <= User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return new Boolean(false);
		}
		try {
			Boolean result = data.updateVolunteer(volunteer);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			logStop(method, "could not update the volunteer");
			throw exception;
		}
	}

	public Boolean createNewVolunteer(User volunteer) throws ServerException {
		final String method = "createNewVolunteer()";
		logStart(method, new String[] { volunteer.toString() });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() <= User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return new Boolean(false);
		}
		try {
			Boolean result = data.createVolunteer(volunteer);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			logStop(method, "could not create the volunteer");
			throw exception;
		}
	}

	public Shelter addShelter(Shelter shelter) throws ServerException {
		final String method = "addShelter()";
		logStart(method, new String[] { shelter.toString() });
		if (shelter.validate() != null) {
			logStop(method, "shelter was invalid");
			return null;
		}
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() <= User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return null;
		}
		try {
			Shelter returnedShelter = data.addShelter(shelter);
			logStop(method);
			return returnedShelter;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not add the shelter");
		return null;
	}

	public Boolean deleteShelter(int shelterId) throws ServerException {
		final String method = "deleteShelter()";
		logStart(method, new String[] { "" + shelterId });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return false;
		}
		try {
			Boolean result = data.deleteShelter(shelterId);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			logStop(method, "could not delete the shelter");
			throw exception;
		}
	}

	public Shelter updateShelter(Shelter shelter) throws ServerException {
		final String method = "updateShelter()";
		logStart(method, new String[] { shelter.toString() });
		if (shelter.validate() != null) {
			logStop(method, "shelter was invalid");
			return null;
		}
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have the right access level");
			return null;
		}
		try {
			Shelter result = data.updateShelter(shelter);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		logStop(method, "could not update the shelter");
		return null;
	}

	public ArrayList getPageOfStories(int shelterId, int offset) {
		final String method = "getPageOfStories()";
		logStart(method, new String[] { "" + shelterId, "" + offset });
		Data data = new Data();
		ArrayList storyList = null;
		try {
			storyList = data.getPageOfStories(shelterId, offset);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (storyList == null) {
			logStop(method, "could not get the page of stories");
		} else {
			logStop(method);
		}
		return storyList;
	}

	public void sendPassword(String email) {
		final String method = "sendPassword()";
		logStart(method, new String[] { "" + email });
		Data data = new Data();
		try {
			data.sendPassword(email);
			logStop(method);
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not send the password");
		}

	}

	public Boolean updatePassword(String password) throws ServerException {
		final String method = "updatePassword()";
		logStart(method, new String[] { password });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		try {
			Boolean result = data.updatePassword(user, password);
			if (result.booleanValue()) {
				logStop(method);
			} else {
				logStop(method, "the result was false");
			}
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not update the password");
			return false;
		}
	}

	public ArrayList getPageOfThankYous(int pageNumber) throws ServerException {
		final String method = "getPageOfThankYous()";
		logStart(method, new String[] { "" + pageNumber });
		Data data = new Data();
		try {
			ArrayList list = data.getPageOfThankYous(pageNumber);
			logStop(method);
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not get the thank you notes page");
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			throw exception;
		}
	}

	public Boolean addThankYou(ThankYou thankyou) throws ServerException {
		final String method = "addThankYouNote()";
		logStart(method, new String[] { thankyou.toString() });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		try {
			boolean result = data.addThankYouNote(thankyou);
			logStop(method);
			return new Boolean(result);
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not add the thank you note");
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			throw exception;
		}

	}

	public Boolean updateThankYou(ThankYou thankyou) throws ServerException {
		final String method = "updateThankYouNote()";
		logStart(method, new String[] { thankyou.toString() });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		try {
			boolean result = data.updateThankYouNote(thankyou);
			logStop(method);
			return new Boolean(result);
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not add the thank you note");
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			throw exception;
		}
	}

	public Boolean deleteThankYou(int id) throws ServerException {
		final String method = "deleteThankYouNote()";
		logStart(method, new String[] { "" + id });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		try {
			boolean result = data.deleteThankYouNote(id);
			logStop(method);
			return new Boolean(result);
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not delete the thank you note");
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			throw exception;
		}
	}

	public ArrayList getThankYous(String headerQuery) throws ServerException {
		final String method = "getThankYous()";
		logStart(method, new String[] { headerQuery });
		Data data = new Data();
		User user = getUser();
		checkTimeout(method, user);
		if (user.getRole() < User.TYPIST) {
			logStop(method, "user did not have right access level");
			return null;
		}
		try {
			ArrayList result = data.getThankYous(headerQuery);
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not get the thank you note");
			ServerException exception = new ServerException();
			exception.setMessage(e.getMessage());
			throw exception;
		}
	}

	public ArrayList getThankYouStats() {
		final String method = "getThankYouStats()";
		logStart(method, new String[] { "" });
		Data data = new Data();
		try {
			ArrayList result = data.getThankYouStats();
			logStop(method);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			logStop(method, "could not get the thank you stats");
			return null;
		}
	}
	
	

}

